package com.iwechat.adapter.mina.entity;

import java.nio.charset.Charset;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.apache.mina.core.buffer.IoBuffer;

import com.iwechat.security.coder.RSACoderSuport;

/**
 * <b>登录报文实例</b> 注意String类型字段使用前需要trim()
 *
 *
 */
public class Connect extends PDUHeader {

    public static final int             command = PDU.COMMAND_CONNECT;
    public static final int             pkgLen  = PDU.HEAD_LEN + 32 + 128;

    private static final RSACoderSuport coder   = RSACoderSuport.getSuport();

    /** 客户端ID : fixed 32 bytes,right padding space */
    private String                      clientID;

    /** RSA数字签名 : fixed 128 bytes. RSA数字签名的数据为整个PDU不含前导符 */
    private byte[]                      sign;

    /**
     * 根据header构造Connect for receive
     *
     *
     * @param Connect
     * @throws Exception
     */
    public Connect(PDUHeader header, IoBuffer buffer, Charset charset) throws Exception {
        this.sequence = header.getSequence();
        this.timestamp = header.getTimestamp();

        byte[] data = new byte[32];
        buffer.get(data);
        this.clientID = new String(data, charset);

        sign = new byte[128];
        buffer.get(sign);
    }

    /**
     * 构造Connect for send
     *
     *
     * @throws Exception
     */
    public Connect(String clientId) {
        this.setSequence(PDUHeader.getSeqNum());
        this.timestamp = System.currentTimeMillis();
        this.setClientID(clientId);
    }

    /**
     * 获取对象的iobuffer,需要先调用 setters
     *
     * @see com.iwechat.adapter.mina.entity.PDUHeader#toIoBuffer(java.nio.charset.CharsetEncoder)
     */
    @Override
    public IoBuffer toIoBuffer(Charset charset) throws Exception {
        IoBuffer buffer = IoBuffer.allocate(pkgLen);
        IoBuffer tosign = IoBuffer.allocate(pkgLen - 128);

        buffer.putInt(pkgLen);
        buffer.putInt(command);
        buffer.putInt(sequence);
        buffer.putLong(timestamp);
        buffer.put(clientID.getBytes(charset));

        tosign.putInt(pkgLen);
        tosign.putInt(command);
        tosign.putInt(sequence);
        tosign.putLong(timestamp);
        tosign.put(clientID.getBytes(charset));
        tosign.flip();
        sign = coder.sign(tosign.array());

        buffer.put(sign);
        buffer.flip();
        return buffer;
    }

    /**
     * 验证客户端签名
     *
     *
     * @param publicKey
     * @param encoder
     * @return
     * @throws Exception
     */
    public boolean verify(String publicKey, Charset charset) throws Exception {
        boolean ok = false;
        IoBuffer buffer = IoBuffer.allocate(pkgLen - 128);
        buffer.putInt(pkgLen);
        buffer.putInt(command);
        buffer.putInt(sequence);
        buffer.putLong(timestamp);

        buffer.put(clientID.getBytes(charset));
        buffer.flip();
        ok = coder.verify(buffer.array(), publicKey, sign);
        return ok;
    }

    public String getSign() {
        try {
            return Base64.encodeBase64String(sign);
        } catch (Exception e) {
        }
        return null;
    }

    public void setClientID(String clientID) {
        this.clientID = StringUtils.rightPad(clientID, 32);
    }

    public String getClientID() {
        return clientID;
    }

    @Override
    public String toString() {
        return "Connect [pkgLen=" + pkgLen + ", command=" + command + ", sequence=" + sequence + ", timestamp=" + timestamp + ", clientID="
                + clientID.trim() + ", sign=" + getSign() + "]";
    }
}
